package cn.gp.chat.websocket;

import cn.gp.chat.commom.resp.MessageVo;
import cn.gp.chat.service.MessageService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@ServerEndpoint("/ws/chat/{userId}")
public class ChatWebSocketServer {
    // 使用 ConcurrentHashMap 存储会话，保证线程安全
    private static final Map<String, Session> SESSIONS = new ConcurrentHashMap<>();
    // 使用原子计数器统计在线用户数
    private static final AtomicInteger ONLINE_COUNT = new AtomicInteger(0);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static MessageService messageService;
    
    // 心跳检测线程池
    private static final ScheduledExecutorService HEARTBEAT_EXECUTOR = Executors.newSingleThreadScheduledExecutor();
    // 心跳超时时间（秒）- 设置为半天
    private static final int HEARTBEAT_TIMEOUT = 60 * 60 * 12;
    // 存储最后心跳时间
    private static final Map<String, Long> LAST_HEARTBEAT = new ConcurrentHashMap<>();
    
    static {
        // 启动心跳检测，每30秒检查一次
        HEARTBEAT_EXECUTOR.scheduleAtFixedRate(() -> {
            long now = System.currentTimeMillis();
            SESSIONS.forEach((userId, session) -> {
                Long lastHeartbeat = LAST_HEARTBEAT.get(userId);
                if (lastHeartbeat != null && (now - lastHeartbeat) > HEARTBEAT_TIMEOUT * 1000) {
                    log.info("用户 {} 心跳超时，关闭连接", userId);
                    try {
                        session.close();
                    } catch (IOException e) {
                        log.error("关闭心跳超时连接失败", e);
                    }
                }
            });
        }, 0, 30, TimeUnit.SECONDS);
    }

    // 注入服务
    public static void setMessageService(MessageService service) {
        messageService = service;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        try {
            // 设置会话配置
            session.setMaxTextMessageBufferSize(64 * 1024);
            session.setMaxBinaryMessageBufferSize(64 * 1024);
            
            // 存储会话
            SESSIONS.put(userId, session);
            // 记录初始心跳时间
            LAST_HEARTBEAT.put(userId, System.currentTimeMillis());
            ONLINE_COUNT.incrementAndGet();
            log.info("用户 {} 已连接，当前在线人数：{}", userId, ONLINE_COUNT.get());
        } catch (Exception e) {
            log.error("WebSocket连接建立失败", e);
            try {
                session.close();
            } catch (IOException ex) {
                log.error("关闭WebSocket连接失败", ex);
            }
        }
    }

    @OnMessage
    public void onMessage(String message, Session session, @PathParam("userId") String userId) {
        try {
            // 更新心跳时间
            LAST_HEARTBEAT.put(userId, System.currentTimeMillis());
            
            // 处理心跳消息
            if ("ping".equals(message)) {
                session.getBasicRemote().sendText("pong");
                return;
            }
            
            MessageVo chatMessageVo = objectMapper.readValue(message, MessageVo.class);
            
            // 异步保存消息到数据库
            CompletableFuture.runAsync(() -> {
                try {
                    messageService.saveMessage(chatMessageVo);
                } catch (Exception e) {
                    log.error("保存消息失败", e);
                }
            });
            
            // 发送消息给接收者
            Session receiverSession = SESSIONS.get(chatMessageVo.getReceiverId().toString());
            if (receiverSession != null && receiverSession.isOpen()) {
                // 更新消息状态为已发送
                chatMessageVo.setStatus(1);
                receiverSession.getBasicRemote().sendText(objectMapper.writeValueAsString(chatMessageVo));
            }
        } catch (RuntimeException e) {
            // 处理业务逻辑错误（如非好友关系）
            log.error("消息发送失败: {}", e.getMessage());
            try {
                session.getBasicRemote().sendText("错误: " + e.getMessage());
            } catch (IOException ex) {
                log.error("发送错误消息失败", ex);
            }
        } catch (Exception e) {
            log.error("处理消息时发生错误", e);
        }
    }

    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId) {
        try {
            SESSIONS.remove(userId);
            LAST_HEARTBEAT.remove(userId);
            ONLINE_COUNT.decrementAndGet();
            log.info("用户 {} 已断开连接，当前在线人数：{}", userId, ONLINE_COUNT.get());
        } catch (Exception e) {
            log.error("处理WebSocket关闭时发生错误", e);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket发生错误", error);
    }

    // 发送消息给指定用户
    public static void sendMessage(String userId, String message) {
        Session session = SESSIONS.get(userId);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                log.error("发送消息失败", e);
            }
        }
    }
    
    // 获取当前在线人数
    public static int getOnlineCount() {
        return ONLINE_COUNT.get();
    }
} 